package aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Date;


/**
 * @Author 肖地洋
 * @Date 2022/5/4 18:37
 *
 * @Aspect 是aspectj的注解
 *         作用:表示当前类是切面类
 *         切面类：是用来给业务方法增加功能的类，在这个类中有切面的功能代码
 *         位置：在类定义的上面
 */
@Aspect
public class MyAspect {
    /**
     * @Before 前置通知注解
     * 定义方法,方法是实现切面功能的
     * 方法的定义要求：
     *             1、各公共方法 public
     *             2、没有返回值
     *             3、方法名称自定义
     *             4、可以有参数也可以没有参数
     *                   如果有参数，参数不是自定义的，有几个参数类型可以使用
     * 属性：value，是切入点表达式，表示切面的功能执行位置
     * 位置：方法上面
     * 特点：1、在目标方法之前先执行的
     *      2、不会改变目标方法的执行结果
     *      3、不会影响目标方法的执行
     *
     */
//    @Before(value = "execution(public void aspectj.SomeServideImpl.doSome(String,int))")
    @Before(value = "execution(String aspectj.SomeServideImpl.doSome(String,int))")
    public void myBefore(JoinPoint jp){
        /**
         *  指定通知方法的参数：Joinpoint
         *  JoinPoint:业务方法，要加入切面功能的业务方法
         *      作用是:可以在通知方法中获取方法执行时的信息，例如方法名称，方法参数等
         *      如果你的通知方法中需要用到方法的信息，就加入jionpoint
         *      这个joinpoint参数的值是框架赋予，必须是第一个参数
         */
        for (Object o:jp.getArgs()) {
            System.out.println(o);
        }
        System.out.println(jp.getSignature()); //获取方法的定义
        System.out.println("前置通知："+new Date());
    }


    /**
     * @AfterReturning 后置通知注解
     * 定义方法,方法是实现切面功能的
     * 方法的定义要求：
     *             1、各公共方法 public
     *             2、没有返回值
     *             3、方法名称自定义
     *             4、有参数，推荐是object
     * 属性：value，是切入点表达式，表示切面的功能执行位置
     * 位置：方法上面
     * 特点：1、在目标方法之后执行的
     *      2、能够获取目标方法的返回值，可以根据这个返回值做不同的处理功能
     *         Object res = doSome();
     *      3、可以修改这个返回值
     *执行：
     *    Object res = doSome();
     *    myAfterReturning(res);
     *
     */

    @AfterReturning(value = "mypt()",returning = "res")
    public void myAfterReturning(Object res){
        /**
         *  指定通知方法的参数：Joinpoint
         *  JoinPoint:业务方法，要加入切面功能的业务方法
         *      作用是:可以在通知方法中获取方法执行时的信息，例如方法名称，方法参数等
         *      如果你的通知方法中需要用到方法的信息，就加入jionpoint
         *      这个joinpoint参数的值是框架赋予，必须是第一个参数
         */
         System.out.println("后置通知");
         if (res=="hello"){
             System.out.println("yes res");
         }else{
             System.out.println("no res");
         }
         res = "AfterReturning";
    }


    /**
     * @Around 环绕通知注解
     * 方法的定义要求：
     *             1、各公共方法 public
     *             2、必须有一个返回值 推荐Object
     *             3、方法名称自定义
     *             4、有固定的参数：ProceedingJoingPoint
     * 属性：value，是切入点表达式，表示切面的功能执行位置
     * 位置：方法上面
     * 特点：1、功能最强的通知
     *      2、可以在方法的前后都增强功能
     *      3、控制目标方法是否被调用执行
     *      4、修改原来目标方法的执行结果，最后影响调用结果
     *
     *环绕通知等同于jdk的动态代理，InvacationHandlder接口
     * 参数：proceedingJoinPoint 等同于Method
     * 作用：执行目标方法
     * 返回值：就是目标方法的返回值，可以被改变
     */
    @Around(value = "mypt()")
    public Object myAfterReturning(ProceedingJoinPoint pjp) throws Throwable {
        Object res = null;
        System.out.println("环绕通知");
        res = pjp.proceed(); //method.invoke(); Object res = doSome();
        System.out.println("环绕通知");
        return res;
    }

    /**
     * @PointCut： 定义和管理切入点，如果项目中有多个切入点表达式是重复的，可以复用的，可以使用pointcut
     *             属性：value 切入点表达式
     *             位置：在自定义的方法上面
     *             特点：当使用@pointcut定义在一个方法的上面，此时这个方法的名称就是切入点表达式的别名
     *             其它通知中就可以使用这个别名来代替切入点表达式了
     *
     */
    @Pointcut(value = "execution(* *..SomeServideImpl.doSome(..))")
    private void mypt(){
        //无需代码
    }


}
